<?php
@set_time_limit(0);
/**
 * 系统运行环境检测
 *
 * @version   $Id: testenv.php 13:57 2011/11/10  $
 * @package   DedeCMS.Administrator
 * @founder   IT柏拉图, https://weibo.com/itprato
 * @author    DedeCMS团队
 * @copyright Copyright (c) 2007 - 2021, 上海卓卓网络科技有限公司 (DesDev, Inc.)
 * @license   http://help.dedecms.com/usersguide/license.html
 * @link      http://www.dedecms.com
 */
require_once dirname(__FILE__) . "/config.php";
CheckPurview('sys_Edit');
$action = isset($action) ? $action : '';
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $GLOBALS['cfg_soft_lang']; ?>">
<title>系统运行目录权限检测</title>
<link rel="stylesheet" type="text/css" href="css/base.css" />
<link rel="stylesheet" type="text/css" href="css/indexbody.css" />
<script type="text/javascript" src="../assets/pkg/jquery/jquery.min.js" ></script>
</head>
<body leftmargin="8" topmargin='8' bgcolor="#FFFFFF" style="min-width:840px">
<?php
if (!function_exists('TestWriteable')) {
    // 检测是否可写
    function TestWriteable($d, $c = true)
    {
        $tfile = '_write_able.txt';
        $d = preg_replace("/\/$/", '', $d);
        $fp = @fopen($d . '/' . $tfile, 'w');
        if (!$fp) {
            if ($c == false) {
                @chmod($d, 0777);
                return false;
            } else {
                return TestWriteable($d, true);
            }

        } else {
            fclose($fp);
            return @unlink($d . '/' . $tfile) ? true : false;
        }
    }
}

if (!function_exists('TestExecuteable')) {
    // 检查是否具目录可执行
    function TestExecuteable($d = '.', $siteuRL = '', $rootDir = '')
    {
        $testStr = '<' . chr(0x3F) . 'p' . chr(hexdec(68)) . chr(112) . "\n\r";
        $filename = md5($d) . '.php';
        $testStr .= 'function test(){ echo md5(\'' . $d . '\');}' . "\n\rtest();\n\r";
        $testStr .= chr(0x3F) . '>';
        $reval = false;
        if (empty($rootDir)) {
            $rootDir = DEDEROOT;
        }

        if (TestWriteable($d)) {
            @file_put_contents($d . '/' . $filename, $testStr);
            $remoteUrl = $siteuRL . '/' . str_replace($rootDir, '', str_replace("\\", '/', realpath($d))) . '/' . $filename;
            $tempStr = @PostHost($remoteUrl);

            $reval = (md5($d) == trim($tempStr)) ? true : false;
            unlink($d . '/' . $filename);
            return $reval;
        } else {
            return -1;
        }
    }
}

if (!function_exists('PostHost')) {
    function PostHost($host, $data = '', $method = 'GET', $showagent = null, $port = null, $timeout = 30)
    {
        $parse = @parse_url($host);
        if (empty($parse)) {
            return false;
        }

        if ((int) $port > 0) {
            $parse['port'] = $port;
        } elseif (!@$parse['port']) {
            $parse['port'] = '80';
        }
        $parse['host'] = str_replace(array('http://', 'https://'), array('', 'ssl://'), "$parse[scheme]://") . $parse['host'];
        if (!$fp = @fsockopen($parse['host'], $parse['port'], $errnum, $errstr, $timeout)) {
            return false;
        }
        $method = strtoupper($method);
        $wlength = $wdata = $responseText = '';
        $parse['path'] = str_replace(array('\\', '//'), '/', @$parse['path']) . "?" . @$parse['query'];
        if ($method == 'GET') {
            $separator = @$parse['query'] ? '&' : '';
            substr($data, 0, 1) == '&' && $data = substr($data, 1);
            $parse['path'] .= $separator . $data;
        } elseif ($method == 'POST') {
            $wlength = "Content-length: " . strlen($data) . "\r\n";
            $wdata = $data;
        }
        $write = "$method $parse[path] HTTP/1.0\r\nHost: $parse[host]\r\nContent-type: application/x-www-form-urlencoded\r\n{$wlength}Connection: close\r\n\r\n$wdata";
        @fwrite($fp, $write);
        while ($data = @fread($fp, 4096)) {
            $responseText .= $data;
        }
        @fclose($fp);
        empty($showagent) && $responseText = trim(stristr($responseText, "\r\n\r\n"), "\r\n");
        return $responseText;
    }
}

$allPath = array();
$needDir = "$cfg_medias_dir|
	$cfg_image_dir|
	$ddcfg_image_dir|
	$cfg_user_dir|
	$cfg_soft_dir|
	$cfg_other_medias|
	$cfg_medias_dir/flink|
	$cfg_cmspath/data|
	$cfg_cmspath/data/$cfg_backup_dir|
	$cfg_cmspath/data/textdata|
	$cfg_cmspath/data/sessions|
	$cfg_cmspath/data/tplcache|
	$cfg_cmspath/data/admin|
	$cfg_cmspath/data/enums|
	$cfg_cmspath/data/mark|
	$cfg_cmspath/data/module|
	$cfg_cmspath/data/rss|
	$cfg_special|
	$cfg_cmspath$cfg_arcdir";
$needDir = explode('|', $needDir);
foreach ($needDir as $key => $val) {
    $allPath[trim($val)] = array(
        'read' => true, // 读取
        'write' => true, // 写入
        'execute' => false, // 执行
    );
}

// 所有栏目目录
$sql = "SELECT typedir FROM #@__arctype ORDER BY id DESC";
$dsql->SetQuery($sql);
$dsql->Execute('al', $sql);
while ($row = $dsql->GetArray('al')) {
    $typedir = str_replace($cfg_basehost, '', $row['typedir']);
    if (preg_match("/^http:|^ftp:/i", $row['typedir'])) {
        continue;
    }

    $typedir = str_replace("{cmspath}", $cfg_cmspath, $row['typedir']);
    $allPath[trim($typedir)] = array(
        'read' => true, // 读取
        'write' => true, // 写入
        'execute' => false, // 执行
    );
}

// 只允许读取,不允许写入的目录
$needDir = array(
    'include',
    'member',
    'plus',
);
// 获取子目录
function GetSondir($d, &$dirname = array())
{
    $dh = dir($d);
    while ($filename = $dh->read()) {
        if (substr($filename, 0, 1) == '.' || is_file($d . '/' . $filename) 
            || preg_match("#^(svn|bak-)#i", $filename)
        ) {
            continue;
        }
        if (is_dir($d . '/' . $filename)) {
            $dirname[] = $d . '/' . $filename;
            GetSondir($d . '/' . $filename, $dirname);
        }
    }
    $dh->close();
    return $dirname;
}

//获取所有文件列表
function preg_ls($path = ".", $rec = false, $pat = "/.*/", $ignoredir = '')
{
    while (substr($path, -1, 1) == "/") {
        $path = substr($path, 0, -1);
    }
    if (!is_dir($path)) {
        $path = dirname($path);
    }
    if ($rec !== true) {
        $rec = false;
    }
    $d = dir($path);
    $ret = array();
    while (false !== ($e = $d->read())) {
        if (($e == ".") || ($e == "..")) {
            continue;
        }
        if ($rec && is_dir($path . "/" . $e) && ($ignoredir == '' || strpos($ignoredir, $e) === false)) {
            $ret = array_merge($ret, preg_ls($path . "/" . $e, $rec, $pat, $ignoredir));
            continue;
        }
        if (!preg_match($pat, $e)) {
            continue;
        }
        $ret[] = $path . "/" . $e;
    }
    return (empty($ret) && preg_match($pat, basename($path))) ? array($path . "/") : $ret;
}

foreach ($needDir as $key => $val) {
    $allPath[trim('/' . $val)] = array(
        'read' => true, // 读取
        'write' => false, // 写入
        'execute' => true, // 执行
    );
    $sonDir = GetSondir(DEDEROOT . '/' . $val);
    foreach ($sonDir as $kk => $vv) {
        $vv = trim(str_replace(DEDEROOT, '', $vv));
        $allPath[$vv] = array(
            'read' => true, // 读取
            'write' => false, // 写入
            'execute' => true, // 执行
        );
    }

}

// 不需要执行的
$needDir = array(
    '/images',
    '/templets',
);
foreach ($needDir as $key => $val) {
    $allPath[trim('/' . $val)] = array(
        'read' => true, // 读取
        'write' => false, // 写入
        'execute' => false, // 执行
    );
    $sonDir = GetSondir(DEDEROOT . '/' . $val);
    foreach ($sonDir as $kk => $vv) {
        $vv = trim(str_replace(DEDEROOT . '/', '', $vv));
        $allPath[$vv] = array(
            'read' => true, // 读取
            'write' => false, // 写入
            'execute' => false, // 执行
        );
    }

}

// 所有js建议只读
$jsDir = array(
    '/images',
    '/templets',
    '/include',
);
foreach ($jsDir as $k => $v) {
    $jsfiles = preg_ls(DEDEROOT . $v, true, "/.*\.(js)$/i");
    foreach ($jsfiles as $k => $v) {
        $vv = trim(str_replace(DEDEROOT . '/', '/', $v));
        $allPath[$vv] = array(
            'read' => true, // 读取
            'write' => false, // 写入
            'execute' => false, // 执行
        );
    }
}
?>
<div id="safemsg">
  <dl style="margin-left:0.5%;margin-right:0.5%; width:97%" id="item1" class="dbox">
    <dt class="lside"><span class="l" style="float:left">系统运行目录权限检测</span><span style="float:right; margin-right:20px"><a href="index_body.php">返回主页</a></span><span style="float:right; margin-right:20px"><a href="http://help.dedecms.com/install-use/apply/2011/1111/2131.html" target="_blank">帮助说明</a></span></dt>
    <dd>
      <div style="padding:10px"> 说明：本程序用于检测DedeCMS站点所涉及的目录权限，并且提供一个全面的检测说明，您可以根据检测报告来配置站点以保证站点更为安全。</div>
      <div id="tableHeader" style="margin-left:10px">
          <table width="784" border="0" cellpadding="0" cellspacing="1" bgcolor="#047700" id="scanTable">
            <thead>
              <tr>
                <td width="40%" height="25" align="center" bgcolor="#E3F1D1">目录</td>
                <td width="20%" height="25" align="center" bgcolor="#E3F1D1">执行</td>
                <td width="20%" height="25" align="center" bgcolor="#E3F1D1">读取</td>
                <td width="20%" height="25" align="center" bgcolor="#E3F1D1">写入</td>
              </tr>
              </thead>
          </table>
      </div>
      <div id="safelist" style="margin-left:10px">
        <div class="install" id="log" style="height: 260px; overflow: auto;">
          <table width="784" border="0" cellpadding="0" cellspacing="1" bgcolor="#047700" id="scanTable">
             <tbody id="mainList">
            </tbody>
          </table>
        </div>
      </div>
    </dd>
  </dl>
</div>
<div style="margin: 0 auto; width:200px"><a href="javascript:startScan();"><img src="images/btn_scan.gif" width="154" height="46" /></a></div>
<script type="text/javascript">
$ = jQuery;
var log = "<?php
foreach ($allPath as $key => $val) {
    if (is_dir(DEDEROOT . $key)) {
        ?><?php echo $key; ?>|<?php
$rs = TestExecuteable(DEDEROOT . $key, $cfg_basehost, $cfg_cmspath);

if ($rs === -1) {
    echo "<font color='red'>无法判断</font>";
} else {
    if ($val['execute'] == true) {
        echo $rs != $val['execute'] ? "<font color='red'>错误(不可执行)</font>" : "<font color='green'>正常(可执行)</font>";
    } else {
        echo $rs != $val['execute'] ? "<font color='red'>错误(可执行)</font>" : "<font color='green'>正常(不可执行)</font>";
    }

}
?>|<?php
if ($val['read'] == true) {
            echo is_readable(DEDEROOT . $key) != $val['read'] ? "<font color='red'>错误(不可读)</font>" : "<font color='green'>正常(可读)</font>";
} else {
    echo is_readable(DEDEROOT . $key) != $val['read'] ? "<font color='red'>错误(可读)</font>" : "<font color='green'>正常(不可读)</font>";
}

?>|<?php
if ($val['write'] == true) {
            echo TestWriteable(DEDEROOT . $key) != $val['write'] ? "<font color='red'>错误(不可写)</font>" : "<font color='green'>正常(可写)</font>";
} else {
    echo TestWriteable(DEDEROOT . $key) != $val['write'] ? "<font color='red'>错误(可写)</font>" : "<font color='green'>正常(不可写)</font>";
}

?><dedecms><?php
    } else {
        ?><?php echo $key; ?>|无需判断|<?php
if ($val['read'] == true) {
            echo is_readable(DEDEROOT . $key) != $val['read'] ? "<font color='red'>错误(不可读)</font>" : "<font color='green'>正常(可读)</font>";
} else {
    echo is_readable(DEDEROOT . $key) != $val['read'] ? "<font color='red'>错误(可读)</font>" : "<font color='green'>正常(不可读)</font>";
}

?>|<?php
if ($val['write'] == true) {
            echo is_writable(DEDEROOT . $key) != $val['write'] ? "<font color='red'>错误(不可写)</font>" : "<font color='green'>正常(可写)</font>";
} else {
    echo is_writable(DEDEROOT . $key) != $val['write'] ? "<font color='red'>错误(可写)</font>" : "<font color='green'>正常(不可写)</font>";
}

?><dedecms><?php
    }
}
?>";
var n = 0;
var timer = 0;
log = log.split('<dedecms>');
function GoPlay(){
    if (n > log.length-1) {
        n=-1;
        clearIntervals();
    }
    if (n > -1) {
        postcheck(n);
        n++;
    }
}
function postcheck(n){
    var item = log[n];
    item = item.split('|');

    document.getElementById('log').scrollTop = document.getElementById('log').scrollHeight;
    if(item == ''){return false;}
    var tempvar='<tr>\r                        <td width="40%" height="23" bgcolor="#FFFFFF">'+item[0]+'</td>\r                    <td width="20%" height="23" align="center" bgcolor="#FEF7C5">'+item[1]+'</td>\r                        <td width="20%" height="23" align="center" bgcolor="#FFFFFF">\r                        '+item[2]+'</td>\r                        <td width="20%" height="23" align="center" bgcolor="#FFFFFF">\r                        '+item[3]+'</td>\r                  </tr>  ';

    //chiledelem.innerHTML = tempvar;
    //document.getElementById("mainList").appendChild(chiledelem);
    $("#mainList").append(tempvar);
    document.getElementById('log').scrollTop = document.getElementById('log').scrollHeight;
}
function setIntervals(){
    timer = setInterval('GoPlay()',50);
}
function clearIntervals(){
    clearInterval(timer);
    //document.getElementById('install').submit();
    alert('全部检测完毕，您可以按照检测结果进行系统权限调整！');
}
//setTimeout(setIntervals, 100);


function changeHeight()
{
    var newheight =  $(window).height() - 170;
    $("#safelist").css('height', newheight + 'px');
    var logheight = newheight;
    $("#log").css('height', logheight + 'px');
}
// 开始检测
function startScan()
{
    setTimeout(setIntervals, 100);
}
$.ready = function(){
    changeHeight();
    $(window).resize(function()
  {
      changeHeight();
  });
};
</script>
</body>
